﻿using System;
using System.Collections.Generic;
using Assist;
using Autodesk.Revit.DB;
using YJKRGeometry;
using ModelCheckUtility;
using ModelCheckUtility.ModelLayer;

namespace EvacuationWidth.ModelLayer
{
	public class AreaPacker_EvacuationWidth : BaseAreaPacker, IAdaptPacker
	{
		internal List<RoomPacker_EvacuationWidth> LstAllRoomPacker
		{
			get
			{
				return this.m_lstAllRoomPacker;
			}
			private set
			{
				this.m_lstAllRoomPacker = value;
			}
		}

		public bool IfEvacuationLevel
		{
			get
			{
				return this.m_bIfEvacuationLevel;
			}
			private set
			{
				this.m_bIfEvacuationLevel = value;
			}
		}

		public double DesignValue
		{
			get
			{
				return this.m_dDesignValue;
			}
			set
			{
				this.m_dDesignValue = value;
			}
		}

		public double RuleValue
		{
			get
			{
				return this.m_dRuleValue;
			}
			set
			{
				this.m_dRuleValue = value;
			}
		}

		public double UseLevelZ
		{
			get
			{
				return this.m_duseLevelZ;
			}
			private set
			{
				this.m_duseLevelZ = value;
			}
		}

		public AreaPacker_EvacuationWidth(Area inputElement, RevitLinkInstance useRevitLinkInstance = null, object[] otherValues = null) : base(inputElement, useRevitLinkInstance, otherValues)
		{
			this.m_thisArea = inputElement;
			this.UseLevelZ = base.m_ThisLevel.Elevation;
		}

		public void AdaptThisPacker()
		{
			this.LstAllRoomPacker = new List<RoomPacker_EvacuationWidth>();
			double num = 1.1;
			foreach (BaseRoomPacker baseRoomPacker in base.LstRoomPackerInThis)
			{
				if (baseRoomPacker != null && baseRoomPacker is RoomPacker_EvacuationWidth)
				{
					RoomPacker_EvacuationWidth roomPacker_EvacuationWidth = baseRoomPacker as RoomPacker_EvacuationWidth;
					roomPacker_EvacuationWidth.AdaptThisPacker();
					this.LstAllRoomPacker.Add(roomPacker_EvacuationWidth);
					this.m_nChairsNumber += roomPacker_EvacuationWidth.ChairsNumber;
					this.m_dTotalStairsWidth += roomPacker_EvacuationWidth.TotalStairsWidth;
				}
			}
			this.m_nChairsNumber = num * this.m_nChairsNumber;
		}

		public void SetBuildingRule(BuildingRuleBean input)
		{
			this.m_useRuleBean = input;
			if (Geometry.IsEqual(this.UseLevelZ, BuildingRuleBean.GroundElevation, 0.1))
			{
				this.IfEvacuationLevel = true;
			}
			this.m_useRuleKindEnum = this.m_useRuleBean.UseRuleKindEnum;
			this.m_useLevelKindEnum = this.m_useRuleBean.CalculateLevelKind(this);
		}

		public bool TryCheck(out AreaCheckResultBean checkResult)
		{
			bool result;
			try
			{
				this.DesignValue = this.CalculateDesignValue();
				this.RuleValue = this.CalculateRuleValue();
				checkResult = new AreaCheckResultBean(base.m_ThisLevel, this.m_thisArea, this.DesignValue, this.RuleValue);
				result = true;
			}
			catch (Exception)
			{
				checkResult = null;
				result = false;
			}
			return result;
		}

		private double CalculateDesignValue()
		{
			List<DoorPacker_EvacuationWidth> allOutDoorsInThisArea = this.GetAllOutDoorsInThisArea();
			double num = this.CalculateAllOutDoorWidth(allOutDoorsInThisArea);
			if (this.IfEvacuationLevel)
			{
				return num;
			}
			return num + this.m_dTotalStairsWidth;
		}

		private double CalculateRuleValue()
		{
			return this.CalculateThisRuleEvacuationWidth();
		}

		private double CalculateAllOutDoorWidth(List<DoorPacker_EvacuationWidth> input)
		{
			double num = 0.0;
			foreach (DoorPacker_EvacuationWidth doorPacker_EvacuationWidth in input)
			{
				num += doorPacker_EvacuationWidth.UseDoorWidth;
			}
			return num;
		}

		private List<DoorPacker_EvacuationWidth> GetAllOutDoorsInThisArea()
		{
			double val = 1.0;
			List<DoorPacker_EvacuationWidth> list = new List<DoorPacker_EvacuationWidth>();
			List<DoorPacker_EvacuationWidth> list2 = new List<DoorPacker_EvacuationWidth>();
			foreach (RoomPacker_EvacuationWidth roomPacker_EvacuationWidth in this.LstAllRoomPacker)
			{
				list2.AddRange(roomPacker_EvacuationWidth.LstAllDoors);
			}
			foreach (DoorPacker_EvacuationWidth doorPacker_EvacuationWidth in list2)
			{
                if (!doorPacker_EvacuationWidth.IfIsActingDoor && ModelCheckUtility.Utility.IfDoorIsOutSideDoor(doorPacker_EvacuationWidth) && doorPacker_EvacuationWidth.IfGetWidthSucess && !Geometry.LessThan(doorPacker_EvacuationWidth.UseDoorWidth, val))
				{
					list.Add(doorPacker_EvacuationWidth);
				}
			}
			return list;
		}

		internal bool TryGetPeopleDensity(out double peopleDensity)
		{
			bool flag = false;
			peopleDensity = 0.0;
            return ModelCheckUtility.Utility.TryReadAreaOtherData(base.ThisArea, out flag, out peopleDensity);
		}

		private double CalculateThisRuleEvacuationWidth()
		{
			double result = 0.0;
			switch (this.m_useRuleKindEnum)
			{
			case RuleKindEnum.OtherBuilding:
				result = this.CalculateRuleEvacuationWidthByRoom();
				break;
			case RuleKindEnum.Theatre:
				result = this.CalculateRuleEvacuationWidthByChairNumberTheatre();
				break;
			case RuleKindEnum.Gym:
				result = this.CalculateRuleEvacuationWidthByChairNumberGym();
				break;
			}
			return result;
		}

		private double CalculateRuleEvacuationWidthByChairNumberGym()
		{
			double num;
			if (this.m_nChairsNumber >= 3000.0 && this.m_nChairsNumber <= 5000.0)
			{
				num = 0.5;
			}
			else if (this.m_nChairsNumber >= 5001.0 && this.m_nChairsNumber <= 10000.0)
			{
				num = 0.43;
			}
			else
			{
				if (this.m_nChairsNumber < 10001.0 || this.m_nChairsNumber > 20000.0)
				{
					return -1.0;
				}
				num = 0.37;
			}
			return num * this.m_nChairsNumber;
		}

		private double CalculateRuleEvacuationWidthByChairNumberTheatre()
		{
			double num;
			if (this.m_nChairsNumber <= 2500.0 && this.m_nChairsNumber > 1200.0 && (this.m_useRuleBean.UseFireLevel == FireLevelEnum.ONE || this.m_useRuleBean.UseFireLevel == FireLevelEnum.TWO))
			{
				num = 0.75;
			}
			else
			{
				if (this.m_nChairsNumber > 1200.0 || this.m_useRuleBean.UseFireLevel != FireLevelEnum.THREE)
				{
					return -1.0;
				}
				num = 1.0;
			}
			return num * this.m_nChairsNumber;
		}

		private double CalculateRuleEvacuationWidthByRoom()
		{
			double eps = 0.01;
			double num = this.m_useRuleBean.CalculateMinEvacuationWidth(this.m_useLevelKindEnum);
			num /= 100.0;
			double num2 = 0.0;
			double num3 = 0.0;
			double num4 = 0.0;
			double num5 = 0.0;
			if (!this.TryGetPeopleDensity(out num4))
			{
				num4 = -1.0;
			}
			foreach (RoomPacker_EvacuationWidth roomPacker_EvacuationWidth in this.LstAllRoomPacker)
			{
				if (roomPacker_EvacuationWidth.TryGetPeopleDensity(out num3))
				{
					num2 += AssistFunc.feet2ToM2(roomPacker_EvacuationWidth.ThisRoom.Area);
					num5 += AssistFunc.feet2ToM2(roomPacker_EvacuationWidth.ThisRoom.Area) * num3 * num;
				}
			}
			double num6 = AssistFunc.feet2ToM2(this.m_thisArea.Area);
			double result;
			if (Geometry.IsEqual(num6, num2, eps) || num2 > num6)
			{
				result = num5;
			}
			else
			{
				double num7 = (num6 - num2) * num4 * num;
				if (Geometry.LessThan(num7, 0.0, eps) && !Geometry.LessThan(num5, 0.0, eps))
				{
					num5 = -num5;
				}
				else if (!Geometry.LessThan(num7, 0.0, eps) && Geometry.LessThan(num5, 0.0, eps))
				{
					num7 = -num7;
				}
				result = num5 + num7;
			}
			return result;
		}

		private double m_duseLevelZ;

		private double m_nChairsNumber;

		private double m_dTotalStairsWidth;

		private BuildingRuleBean m_useRuleBean;

		private RuleKindEnum m_useRuleKindEnum;

		private LevelKindEnum m_useLevelKindEnum;

		private bool m_bIfEvacuationLevel;

		private double m_dDesignValue;

		private double m_dRuleValue;

		private List<RoomPacker_EvacuationWidth> m_lstAllRoomPacker = new List<RoomPacker_EvacuationWidth>();

		private Area m_thisArea;
	}
}
